/***********************************************************

  AVR Fast Access I/O Class

  Copyright (C) 2009-2011 Jason Vreeland, Matt Reba, Tom Harkaway

    This file is part of OpenTroller Framework.

    OpenTroller Framework is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    OpenTroller Framework is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenTroller Framework.  If not, see <http://www.gnu.org/licenses/>.

    More information available at https://launchpad.net/opentroller-framework/

    Original Author (FastPin Library):  Jason Vreeland

	Modified By:      Tom Harkaway, Feb, 2011
	Modifications:
		Generalize FastPin library so that it can be used on Arduino platforms, specifically
		the Arduino Mega.

		Incorporate PinChange interrupt (PCInt) support. On the BrewTroller, all 32 pins can
		be configured as PCInt pins. That is not true of other Arduino platforms, such as 
		the Adrunio Mega.
	
	Modified By:	Matt Reba, Dec, 2011
	Modifications:
		Incorporated into OpenTroller Framework as AVR Fast Access I/O Class (AVRIO)
*/

#ifndef _OT_AVRIO_H
#define _OT_AVRIO_H

// Uncomment to add access to debug routines to Serial debug dump routines
//#define FASTPIN_DEBUG

#include <pins_arduino.h>
#include <avr/io.h>
#include <WProgram.h>
#include "OT_HWProfile.h"

#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)   // Sanguino
#define MAX_PIN 31
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)  // Arduino ATMega
#define MAX_PIN 69
#elif defined(__AVR_ATmega168__) // Arduino ATMega
#define MAX_PIN 20
#else
#error FastPin only defined for ATMega (1280/2560) and Sanguino (644P/1284P) processors
#endif

// Port IDs
//
#define NOT_A_PORT 0
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12

#define NO_PCINT 255


typedef void (*PCIntvoidFuncPtr)(void);


/********************************************************/
// PinChange Interrupt Support Classes
//

// PCI_Port class 
//  Manages the collection PinChangeInterrupts (PCI) for a given port. 
//
class PCI_Port 
{
  // constructor
  PCI_Port(int index, int port, volatile uint8_t& maskReg) :
      _index(index),
      _inputReg(*portInputRegister(port)),
      _pcmskReg(maskReg),
      _pcicrBit(1 << index),
      _lastVal(0)	
  {
    for (int i = 0; i < 9; i++) 
      _pcIntPinArray[i] = NULL;
  }

public:
  static PCI_Port	s_pcIntPorts[]; // static PCI_Port Array

  void PCintHandler();              // PinChange Interrupt Handler
  void PCintHandler2();              // PinChange Interrupt Handler

protected:

  // embedded PCI_Pin class
  //
  class PCI_Pin 
  {
  public:
    PCI_Pin() :
        _pinID(0),
        _pinMask(0),
        _pinMode(0),
        _func((PCIntvoidFuncPtr)NULL)
  { }

    byte _pinID;    // pin number
    byte _pinMask;  // bit mask 
    byte _pinMode;  // CHANGE, RISING, FALLING

    PCIntvoidFuncPtr _func; // user function 

    // static PCintPins Array
    static PCI_Pin s_pcIntPins[MAX_PIN_CHANGE_PINS];

  }; // PCI_Pin class

public:
  int  addPin(byte pin, byte mode, byte mask, PCIntvoidFuncPtr userFunc);
  bool delPin(byte pinID);

protected:
  byte              _index;
  volatile byte&		_inputReg;  // port input register (will need to move to PCI_Pin)
  volatile byte&		_pcmskReg;  // port bit Mask Register
  const byte			  _pcicrBit;  // PCI enable bit
  byte			        _lastVal;   // last input value

  //// PCI_Pin array for this port
  PCI_Pin*	_pcIntPinArray[9];	// extra entry is a barrier

public:
#ifdef FASTPIN_DEBUG
  int getIndex() { return _index; }
  void dumpPCIntPin(PCI_Pin* pPin);
  void dumpPCIntPinArray();
#endif

};  // PCI_Port class


/********************************************************/
// AVR Fast Access I/O Class
//

class AVRIO
{
	public:
	AVRIO(void);
	AVRIO(byte);
	AVRIO(byte pinID, byte pinDir);
	void setup(byte pinID, byte pinDir);

	void setPin(byte);
	void setDir(byte);

	void set(byte);
	void set(void);
	void clear(void);
	bool get(void);
	void toggle(void);

	byte getPin(void)   { return _pinID; }
	byte getDir(void)   { return _dir; }
	byte getPort(void)  { return _port; }
	byte getMask(void)  { return _mask; }

	int  attachPCInt(int modePC, PCIntvoidFuncPtr userFunc);
	bool detachPCInt();

	private:
	byte _pinID;  // pin number
	byte _dir;    // direction
	byte _port;   // port ID
	byte _mask;   // mask
};


// Mapping of PIN ID to PCInt port
//
extern const uint8_t PROGMEM digitalpin_to_pcint_PGM[];
#define digitalPinToPCINT(P) ( pgm_read_byte( digitalpin_to_pcint_PGM + (P) ) )


#endif
